﻿using System;
using System.Collections.Generic;
using System.DirectoryServices.AccountManagement;
using System.Linq;
using System.Reflection;
using System.Security;
using System.Security.Principal;
using System.Text;
using Microsoft.Win32;
using Obviex.CipherLite;
using Umbrella.Whs;

namespace Umbrella.Whs.SharePoint
{
    public sealed class SharePointServiceAccount : UserAccount
    {
        private const string SharePointUserPasswordName = "SPUserData";

        public override string UserNameOnly
        {
            get { return "SharePointUser"; }
        }

        public override string FullName
        {
            get { return Properties.Resources.txtSharePointServiceAccountFullName; }
        }

        public SecureString Password
        {
            get; 
            private set;
        }

        private static string Salt
        {
            get
            {
                var ea = Assembly.GetEntryAssembly();

                if (ea == null)
                    return string.Empty;

                return ea.GetName().Name;
            }
            
        }

        public bool VerifyCredentials()
        {
            using (var pc = new PrincipalContext(ContextType.Machine))
            {
                return pc.ValidateCredentials(this.UserNameOnly, this.Password.ToClrString());
            }
        }

        public static SharePointServiceAccount Load()
        {
            // load encrypted password
            var key = UmbrellaRegistry.OpenKey();

            var pwd = key.GetValue(SharePointUserPasswordName) as byte[];

            if (pwd == null)
                throw new InvalidOperationException("no password stored");

            // parse password
            var r = new SharePointServiceAccount();
            var ss = new SecureString();

            foreach (var c in Dpapi.Decrypt(pwd, Salt).ToCharArray())
            {
                ss.AppendChar(c);
            }

            ss.MakeReadOnly();

            r.Password = ss;

            return r;
        }

        public static bool Exists()
        {
            var r = new SharePointServiceAccount();

            using (var pc = new PrincipalContext(ContextType.Machine))
            {
                return (UserPrincipal.FindByIdentity(
                    pc,
                    IdentityType.Name,
                    r.UserNameOnly
                    ) != null);
            }
        }

        public static SharePointServiceAccount Create()
        {
            if (Exists())
                throw new InvalidOperationException("user already exists");

            // generate random password
            var r = new SharePointServiceAccount();
            var pwd = RandomPassword.Generate(15, 20);

            // create user
            using (var pc = new PrincipalContext(ContextType.Machine))
            {
                var user = new UserPrincipal(pc)
                {
                    Name = r.UserNameOnly,
                    DisplayName = r.FullName,
                    Description = Properties.Resources.txtSharePointServiceAccountDesc,
                    UserCannotChangePassword = true,
                    PasswordNeverExpires = true,
                };

                user.SetPassword(pwd);
                user.Save();
            }

            // encrypt and save password
            var pwdData = Dpapi.Encrypt(Dpapi.KeyType.Machine, Salt, pwd);

            var key = UmbrellaRegistry.OpenKey();

            key.SetValue(SharePointUserPasswordName, pwdData, RegistryValueKind.Binary);

            // parse password
            var ss = new SecureString();

            foreach (var c in pwd.ToCharArray())
            {
                ss.AppendChar(c);
            }

            ss.MakeReadOnly();

            r.Password = ss;

            return r;
        }

        private SharePointServiceAccount()
        {
        }
    }
}
